package org.jma.lib.utils.strings;

import java.sql.Clob;
import java.sql.SQLException;
import java.text.*;
import java.util.*;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;


/**
 * This class contains a number of static methods that can be used to
 * validate the format of Strings, typically received as input from
 * a user, and to format values as Strings that can be used in
 * HTML output without causing interpretation problems.
 *
 * @author Hans Bergsten, Gefion software <hans@gefionsoftware.com>
 * @version 1.0
 */
public class StringFormat {
    // Static format objects
    private static SimpleDateFormat dateFormat = new SimpleDateFormat();
    private static DecimalFormat numberFormat = new DecimalFormat();

    /**
     * Returns true if the specified date string represents a valid
     * date in the specified format.
     *
     * @param dateString a String representing a date/time.
     * @param dateFormatPattern a String specifying the format to be used
     *   when parsing the dateString. The pattern is expressed with the
     *   pattern letters defined for the java.text.SimpleDateFormat class.
     * @return true if valid, false otherwise
     */
    public static boolean isValidDate(String dateString, String dateFormatPattern) {
        Date validDate = null;
        synchronized (dateFormat) { 
            try {
                dateFormat.applyPattern(dateFormatPattern);
                dateFormat.setLenient(false);
                validDate = dateFormat.parse(dateString);
            }
            catch (ParseException e) {
                // Ignore and return null
            }
        }
        return validDate != null;
    }
    
    /**
     * Returns true if the specified number string represents a valid
     * integer in the specified range.
     *
     * @param numberString a String representing an integer
     * @param min the minimal value in the valid range
     * @param min the maximal value in the valid range
     * @return true if valid, false otherwise
     */
    public static boolean isValidInteger(String numberString, int min, int max) {
        Integer validInteger = null;
        try {
            Number aNumber = numberFormat.parse(numberString);
            int anInt = aNumber.intValue();
            if (anInt >= min && anInt <= max) {
                validInteger = new Integer(anInt);
            }
        }
        catch (ParseException e) {
            // Ignore and return null
        }
        return validInteger != null;
    }
    
    /**
     * Returns true if the email string contains an at sign ("@") and
     * at least one dot ("."), i.e. "hans@gefionsoftware.com" is accepted
     * but "hans@gefionsoftware" is not. Note! This rule is not always
     * correct (e.g. on an intranet it may be okay with just a name) and
     * does not gurantee a valid Internet email address but it takes
     * care of the most obvious Internet mail address format errors.
     *
     * @param emailAddrString a String representing an email address
     * @return true if valid, false otherwise
     */
    public static boolean isValidEmailAddr(String emailAddrString) {
        boolean isValid = false;
        if (emailAddrString != null && 
            emailAddrString.indexOf("@") != -1 &&
            emailAddrString.indexOf(".") != -1) {
            isValid = true;
        }
        return isValid;
    }

    /**
     * Returns true if the specified string matches a string in the set
     * of provided valid strings, ignoring case if specified.
     *
     * @param value the String validate
     * @param validStrings an array of valid Strings
     * @param ignoreCase if true, case is ignored when comparing the value
     *  to the set of validStrings
     * @return true if valid, false otherwise
     */
    public static boolean isValidString(String value, String[] validStrings, 
            boolean ignoreCase) {
        boolean isValid = false;
        for (int i = 0; validStrings != null && i < validStrings.length; i++) {
            if (ignoreCase) {
                if (validStrings[i].equalsIgnoreCase(value)) {
                    isValid = true;
                    break;
                }
            }
            else {
                if (validStrings[i].equals(value)) {
                    isValid = true;
                    break;
                }
            }
        }
        return isValid;
    }
	public static String toHTMLString(String in) {
		   StringBuffer out = new StringBuffer();
		   for (int i = 0; in != null && i < in.length(); i++) {
			   char c = in.charAt(i);
			   Integer charCode=new Integer(c);
			   if (charCode.intValue() > 127){
				   out.append("&#"+charCode+";");
			   }else if (c == '\'') {
				   out.append("&#39;");
			   }
			   else if (c == '\"') {
				   out.append("&#34;");
			   }
			   else if (c == '<') {
				   out.append("&lt;");
			   }
			   else if (c == '>') {
				   out.append("&gt;");
			   }
			   else if (c == '&') {
				   out.append("&amp;");
			   }
			   else if (c == '\n') {
				   out.append("&#13;&#10;");
			   }
			   else {
				   out.append(c);
			   }
		   }
		   return out.toString();
	   }
 /*   
     * Returns the specified string converted to a format suitable for
     * HTML. All signle-quote, double-quote, greater-than, less-than and
     * ampersand characters are replaces with their corresponding HTML
     * Character Entity code.
     *
     * @param in the String to convert
     * @return the converted String
     
    public static String toJavaScriptString(String in) {
        StringBuffer out = new StringBuffer();
        for (int i = 0; in != null && i < in.length(); i++) {
            char c = in.charAt(i);
            if (c == '\'') {
                out.append("\\\'");
            }
            else if (c == '\"') {
                out.append("\\\"");
            }
            else if (c == '\t') {
                out.append("\\t");
            }
            else if (c == '\r') {
                out.append("\\r ");
            }
            else if (c == '&') {
                out.append("&");
            }
			else if (c == '\n') {
				out.append("\\n");
			}
            else {
                out.append(c);
            }
        }
        return out.toString();
    }
*/

    /**
     * Converts a String to a Date, using the specified pattern.
     * (see java.text.SimpleDateFormat for pattern description)
     *
     * @param dateString the String to convert
     * @param dateFormatPattern the pattern
     * @return the corresponding Date
     * @exception ParseException, if the String doesn't match the pattern
     */
    public static Date toDate(String dateString, String dateFormatPattern) 
        throws ParseException {
        Date date = null;
        if (dateFormatPattern == null) {
            dateFormatPattern = "yyyy-MM-dd";
        }
        synchronized (dateFormat) { 
            dateFormat.applyPattern(dateFormatPattern);
            dateFormat.setLenient(false);
            date = dateFormat.parse(dateString);
        }
        return date;
    }

    /**
     * Converts a String to a Number, using the specified pattern.
     * (see java.text.NumberFormat for pattern description)
     *
     * @param numString the String to convert
     * @param numFormatPattern the pattern
     * @return the corresponding Number
     * @exception ParseException, if the String doesn't match the pattern
     */
    public static Number toNumber(String numString, String numFormatPattern) 
        throws ParseException {
        Number number = null;
        if (numFormatPattern == null) {
            numFormatPattern = "######.##";
        }
        synchronized (numberFormat) { 
            numberFormat.applyPattern(numFormatPattern);
            number = numberFormat.parse(numString);
        }
        return number;
    }

    /**
     * Replaces one string with another throughout a source string.
     *
     * @param in the source String
     * @param from the sub String to replace
     * @param to the sub String to replace with
     * @return a new String with all occurences of from replaced by to
     */
    public static String replaceInString(String in, String from, String to) {
        if (in == null || from == null || to == null) {
            return in;
        }

        StringBuffer newValue = new StringBuffer();
        char[] inChars = in.toCharArray();
        int inLen = inChars.length;
        char[] fromChars = from.toCharArray();
        int fromLen = fromChars.length;

        for (int i = 0; i < inLen; i++) {
            if (inChars[i] == fromChars[0] && (i + fromLen) <= inLen) {
                boolean isEqual = true;
                for (int j = 1; j < fromLen; j++) {
                    if (inChars[i + j] != fromChars[j]) {
                        isEqual = false;
                        break;
                    }
                }
                if (isEqual) {
                    newValue.append(to);
                    i += fromLen - 1;
                }
                else {
                    newValue.append(inChars[i]);
                }
            }
            else {
                newValue.append(inChars[i]);
            }
        }
        return newValue.toString();
    }
    
    
    
    
	// Java and JavaScript
	//--------------------------------------------------------------------------
	/**
	 * <p>Escapes the characters in a <code>String</code> using Java String rules.</p>
	 *
	 * <p>Deals correctly with quotes and control-chars (tab, backslash, cr, ff, etc.) </p>
	 *
	 * <p>So a tab becomes the characters <code>'\\'</code> and
	 * <code>'t'</code>.</p>
	 *
	 * <p>The only difference between Java strings and JavaScript strings
	 * is that in JavaScript, a single quote must be escaped.</p>
	 *
	 * <p>Example:
	 * <pre>
	 * input string: He didn't say, "Stop!"
	 * output string: He didn't say, \"Stop!\"
	 * </pre>
	 * </p>
	 *
	 * @param str  String to escape values in, may be null
	 * @return String with escaped values, <code>null</code> if null string input
	 */
	public static String escapeJava(String str) {
		return escapeJavaStyleString(str, false);
	}

	/**
	 * <p>Escapes the characters in a <code>String</code> using Java String rules to
	 * a <code>Writer</code>.</p>
	 * 
	 * <p>A <code>null</code> string input has no effect.</p>
	 * 
	 * @see #escapeJava(java.lang.String)
	 * @param out  Writer to write escaped string into
	 * @param str  String to escape values in, may be null
	 * @throws IllegalArgumentException if the Writer is <code>null</code>
	 * @throws IOException if error occurs on underlying Writer
	 */
	public static void escapeJava(Writer out, String str) throws IOException {
		escapeJavaStyleString(out, str, false);
	}

	/**
	 * <p>Escapes the characters in a <code>String</code> using JavaScript String rules.</p>
	 * <p>Escapes any values it finds into their JavaScript String form.
	 * Deals correctly with quotes and control-chars (tab, backslash, cr, ff, etc.) </p>
	 *
	 * <p>So a tab becomes the characters <code>'\\'</code> and
	 * <code>'t'</code>.</p>
	 *
	 * <p>The only difference between Java strings and JavaScript strings
	 * is that in JavaScript, a single quote must be escaped.</p>
	 *
	 * <p>Example:
	 * <pre>
	 * input string: He didn't say, "Stop!"
	 * output string: He didn\'t say, \"Stop!\"
	 * </pre>
	 * </p>
	 *
	 * @param str  String to escape values in, may be null
	 * @return String with escaped values, <code>null</code> if null string input
	 */
	public static String escapeJavaScript(String str) {
		return escapeJavaStyleString(str, true);
	}

	/**
	 * <p>Escapes the characters in a <code>String</code> using JavaScript String rules
	 * to a <code>Writer</code>.</p>
	 * 
	 * <p>A <code>null</code> string input has no effect.</p>
	 * 
	 * @see #escapeJavaScript(java.lang.String)
	 * @param out  Writer to write escaped string into
	 * @param str  String to escape values in, may be null
	 * @throws IllegalArgumentException if the Writer is <code>null</code>
	 * @throws IOException if error occurs on underlying Writer
	 **/
	public static void escapeJavaScript(Writer out, String str) throws IOException {
		escapeJavaStyleString(out, str, true);
	}

	private static String escapeJavaStyleString(String str, boolean escapeSingleQuotes) {
		if (str == null) {
			return "";
		}
		try {
			StringWriter writer = new StringWriter(str.length() * 2);
			escapeJavaStyleString(writer, str, escapeSingleQuotes);
			return writer.toString();
		} catch (IOException ioe) {
			// this should never ever happen while writing to a StringWriter
			ioe.printStackTrace();
			return null;
		}
	}

	private static void escapeJavaStyleString(Writer out, String str, boolean escapeSingleQuote) throws IOException {
		if (out == null) {
			throw new IllegalArgumentException("The Writer must not be null");
		}
		if (str == null) {
			return;
		}
		int sz;
		sz = str.length();
		for (int i = 0; i < sz; i++) {
			char ch = str.charAt(i);

			// handle unicode
			if (ch > 0xfff) {
				out.write("\\u" + hex(ch));
			} else if (ch > 0xff) {
				out.write("\\u0" + hex(ch));
			} else if (ch > 0x7f) {
				out.write("\\u00" + hex(ch));
			} else if (ch < 32) {
				switch (ch) {
					case '\b':
						out.write('\\');
						out.write('b');
						break;
					case '\n':
						out.write('\\');
						out.write('n');
						break;
					case '\t':
						out.write('\\');
						out.write('t');
						break;
					case '\f':
						out.write('\\');
						out.write('f');
						break;
					case '\r':
						out.write('\\');
						out.write('r');
						break;
					default :
						if (ch > 0xf) {
							out.write("\\u00" + hex(ch));
						} else {
							out.write("\\u000" + hex(ch));
						}
						break;
				}
			} else {
				switch (ch) {
					case '\'':
						if (escapeSingleQuote) {
						  out.write('\\');
						}
						out.write('\'');
						break;
					case '"':
						out.write('\\');
						out.write('"');
						break;
					case '\\':
						out.write('\\');
						out.write('\\');
						break;
					default :
						out.write(ch);
						break;
				}
			}
		}
	}

	/**
	 * <p>Returns an upper case hexadecimal <code>String</code> for the given
	 * character.</p>
	 * 
	 * @param ch The character to convert.
	 * @return An upper case hexadecimal <code>String</code>
	 */
	private static String hex(char ch) {
		return Integer.toHexString(ch).toUpperCase();
	}

	/**
	 * <p>Unescapes any Java literals found in the <code>String</code>.
	 * For example, it will turn a sequence of <code>'\'</code> and
	 * <code>'n'</code> into a newline character, unless the <code>'\'</code>
	 * is preceded by another <code>'\'</code>.</p>
	 * 
	 * @param str  the <code>String</code> to unescape, may be null
	 * @return a new unescaped <code>String</code>, <code>null</code> if null string input
	 */
	public static String unescapeJava(String str) {
		if (str == null) {
			return null;
		}
		try {
			StringWriter writer = new StringWriter(str.length());
			unescapeJava(writer, str);
			return writer.toString();
		} catch (IOException ioe) {
			// this should never ever happen while writing to a StringWriter
			ioe.printStackTrace();
			return null;
		}
	}

	/**
	 * <p>Unescapes any Java literals found in the <code>String</code> to a
	 * <code>Writer</code>.</p>
	 *
	 * <p>For example, it will turn a sequence of <code>'\'</code> and
	 * <code>'n'</code> into a newline character, unless the <code>'\'</code>
	 * is preceded by another <code>'\'</code>.</p>
	 * 
	 * <p>A <code>null</code> string input has no effect.</p>
	 * 
	 * @param out  the <code>Writer</code> used to output unescaped characters
	 * @param str  the <code>String</code> to unescape, may be null
	 * @throws IllegalArgumentException if the Writer is <code>null</code>
	 * @throws IOException if error occurs on underlying Writer
	 */
	public static void unescapeJava(Writer out, String str) throws IOException {
		if (out == null) {
			throw new IllegalArgumentException("The Writer must not be null");
		}
		if (str == null) {
			return;
		}
		int sz = str.length();
		StringBuffer unicode = new StringBuffer(4);
		boolean hadSlash = false;
		boolean inUnicode = false;
		for (int i = 0; i < sz; i++) {
			char ch = str.charAt(i);
			if (inUnicode) {
				// if in unicode, then we're reading unicode
				// values in somehow
				unicode.append(ch);
				if (unicode.length() == 4) {
					// unicode now contains the four hex digits
					// which represents our unicode character
						int value = Integer.parseInt(unicode.toString(), 16);
						out.write((char) value);
						unicode.setLength(0);
						inUnicode = false;
						hadSlash = false;

				}
				continue;
			}
			if (hadSlash) {
				// handle an escaped value
				hadSlash = false;
				switch (ch) {
					case '\\':
						out.write('\\');
						break;
					case '\'':
						out.write('\'');
						break;
					case '\"':
						out.write('"');
						break;
					case 'r':
						out.write('\r');
						break;
					case 'f':
						out.write('\f');
						break;
					case 't':
						out.write('\t');
						break;
					case 'n':
						out.write('\n');
						break;
					case 'b':
						out.write('\b');
						break;
					case 'u':
						{
							// uh-oh, we're in unicode country....
							inUnicode = true;
							break;
						}
					default :
						out.write(ch);
						break;
				}
				continue;
			} else if (ch == '\\') {
				hadSlash = true;
				continue;
			}
			out.write(ch);
		}
		if (hadSlash) {
			// then we're in the weird case of a \ at the end of the
			// string, let's output it anyway.
			out.write('\\');
		}
	}

	/**
	 * <p>Unescapes any JavaScript literals found in the <code>String</code>.</p>
	 *
	 * <p>For example, it will turn a sequence of <code>'\'</code> and <code>'n'</code>
	 * into a newline character, unless the <code>'\'</code> is preceded by another
	 * <code>'\'</code>.</p>
	 *
	 * @see #unescapeJava(String)
	 * @param str  the <code>String</code> to unescape, may be null
	 * @return A new unescaped <code>String</code>, <code>null</code> if null string input
	 */
	public static String unescapeJavaScript(String str) {
		return unescapeJava(str);
	}

	/**
	 * <p>Unescapes any JavaScript literals found in the <code>String</code> to a
	 * <code>Writer</code>.</p>
	 *
	 * <p>For example, it will turn a sequence of <code>'\'</code> and <code>'n'</code>
	 * into a newline character, unless the <code>'\'</code> is preceded by another
	 * <code>'\'</code>.</p>
	 *
	 * <p>A <code>null</code> string input has no effect.</p>
	 * 
	 * @see #unescapeJava(Writer,String)
	 * @param out  the <code>Writer</code> used to output unescaped characters
	 * @param str  the <code>String</code> to unescape, may be null
	 * @throws IllegalArgumentException if the Writer is <code>null</code>
	 * @throws IOException if error occurs on underlying Writer
	 */
	public static void unescapeJavaScript(Writer out, String str) throws IOException {
		unescapeJava(out, str);
	}

	public static String replaceAll(
		    final String aInput,
		    final String aOldPattern,
		    final String aNewPattern
		  ){
		     if ( aOldPattern.equals("") ) {
		        throw new IllegalArgumentException("Old pattern must have content.");
		     }

		     final StringBuffer result = new StringBuffer();
		     //startIdx and idxOld delimit various chunks of aInput; these
		     //chunks always end where aOldPattern begins
		     int startIdx = 0;
		     int idxOld = 0;
		     while ((idxOld = aInput.indexOf(aOldPattern, startIdx)) >= 0) {
		       //grab a part of aInput which does not include aOldPattern
		       result.append( aInput.substring(startIdx, idxOld) );
		       //add aNewPattern to take place of aOldPattern
		       result.append( aNewPattern );

		       //reset the startIdx to just after the current match, to see
		       //if there are any further matches
		       startIdx = idxOld + aOldPattern.length();
		     }
		     //the final chunk will go to the end of aInput
		     result.append( aInput.substring(startIdx) );
		     return result.toString();
		  }


	public static String getStringValue(Object val){
		try{
		Object value=val;
		Class valueClass=val.getClass();
		
		if (valueClass.isAssignableFrom(java.sql.Date.class)){
			java.sql.Date diaSql = (java.sql.Date) value;
			DateFormat df=DateFormat.getDateInstance(DateFormat.MEDIUM);
			df.setCalendar(Calendar.getInstance());	
			return df.format(diaSql);
		}
    	
		if (valueClass.isAssignableFrom(java.sql.Timestamp.class)){
			java.sql.Timestamp time = (java.sql.Timestamp) value;
			DateFormat df=DateFormat.getDateInstance(DateFormat.MEDIUM);
			df.setCalendar(Calendar.getInstance());	
			return df.format(time);
		}
		
		if (valueClass.isAssignableFrom(java.lang.String.class)){

			return (String)value.toString();
		}
    	
    	

    	
		if (valueClass.isAssignableFrom(Clob.class)){
			Clob clob=(Clob)value;
			String stringValue = null;
			try {
				stringValue = clob.getSubString(0, (int) clob.length());
			} catch (SQLException e) {
				e.printStackTrace();
			}
			return stringValue;
		}
    	

    	
		if (value!=null){
			String v=value.toString();
			v=v.equals("null")?null:v;
			return v;
		} 
		return null;
		}
		catch (Exception e){
		return null;
		}
	}
	
}
 
